Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix: initial config should not influence sslv2 #4987

Open
wants to merge 1 commit into
base: main
Choose a base branch
from

Conversation

jmayclin
Copy link
Contributor

@jmayclin jmayclin commented Dec 19, 2024

Resolved issues:

#4585

Description of changes:

This PR separate out parsing and processing for sslv2 formatted client hellos. Previously both items were handled by s2n_sslv2_client_hello_recv. Splitting these out into two functions allows us to

  1. parse the sslv2 client hello without touching anything on the config
  2. invoke the client hello callback
  3. then process the sslv2 client hello (which requires touching the config)

Call-outs:

This code is basically stolen respectfully appropriated from an earlier draft of #4676 , so thanks @maddeleine!

Testing:

I added a unit test that confirms the config isn't de-referenced in the parsing of the SSLV2 client hello.

By submitting this pull request, I confirm that my contribution is made under the terms of the Apache 2.0 license.

Co-authored-by: maddeleine <59030281+maddeleine@users.noreply.github.com>
@github-actions github-actions bot added the s2n-core team label Dec 19, 2024
@@ -102,7 +102,7 @@ int main(int argc, char **argv)
EXPECT_SUCCESS(s2n_stuffer_write(&server_conn->handshake.io, &client_hello));
EXPECT_SUCCESS(s2n_client_hello_recv(server_conn));

EXPECT_EQUAL(server_conn->server_protocol_version, i == 0 ? S2N_TLS12 : S2N_TLS13);
EXPECT_EQUAL(server_conn->server_protocol_version, S2N_TLS12);
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

conn->server_protocol_version is set to s2n_highest_protocol_version in s2n_connection_new. s2n_highest_protocol_version is either TLS 1.2 or TLS 1.3, depending on whether s2n_disable/enable_tls13_test functions have been used.

Previously

server_protocol_version was never modified for SSLv2 client hellos. This line was just asserting on s2n_highest_protocol_version which was toggled between test runs by s2n_disable/enable_tls13_test.

Proposed

server_protocol_version is now modified by this section in process_client_hello.

if (!s2n_connection_supports_tls13(conn) || !s2n_security_policy_supports_tls13(security_policy)) {
conn->server_protocol_version = MIN(conn->server_protocol_version, S2N_TLS12);
conn->actual_protocol_version = MIN(conn->server_protocol_version, S2N_TLS12);
}

From my reading/audit of the codebase, server_protocol_version is mostly used for various checks and assertions related to downgrade protection. From the brief audit that I did, I didn't see any places that this would be a noticeable behavior change, but this part of the codebase is pretty new to me and our SSLV2 test coverage is pretty low ☹️

I'll also throw out that server_protocol_version being set to TLS13 while using SSLV2 client hellos seems suspicious given this RFC requirement

Implementations MUST NOT negotiate TLS 1.3 or later using an SSL version 2.0 compatible CLIENT-HELLO.
https://www.rfc-editor.org/rfc/rfc8446#appendix-D.5

Note: I think the code chunk above should just always be assigning S2N_TLS12. When I made that change, all the test cases continued to pass exception one of the renegotiate ones. Need to investigate further

Copy link
Contributor

@lrstewart lrstewart Jan 2, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

server_protocol_version was never modified for SSLv2 client hellos

That's definitely a bug. Later code is going to assume that server_protocol_version was set properly, regardless of what it's currently used for.

But the TLS1.3 case not working makes sense. SSLv2 ClientHellos don't contain extensions, and the only way to negotiate TLS1.3 is via extension. Even if that wasn't the case, we're using a hard-coded ClientHello so s2n_disable/enable_tls13_test would have no effect on it.

So yes, your fix is correct. But it's arguable whether the two different test setups are even necessary. Yes, s2n_disable/enable_tls13_test would still affect the server itself, but we're only setting the "tls12_config" on the server. I think this test needs a little more attention.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Maybe just remove s2n_enable/disable_tls13_in_test() for this test? If we're explicitly setting the config then it's not necessary.

@jmayclin jmayclin marked this pull request as ready for review December 19, 2024 23:51
Comment on lines 29 to +30
int s2n_client_hello_send(struct s2n_connection *conn);
int s2n_parse_client_hello(struct s2n_connection *conn);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If you're going to make this method "public" than you should probably give it a better name: s2n_client_hello_parse.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Am I missing something 🤔 ? Why do you need to make this method public at all?

Comment on lines +597 to +603
if (conn->client_hello_version == S2N_SSLv2) {
POSIX_GUARD(s2n_set_cipher_as_sslv2_server(conn, client_hello->cipher_suites.data,
client_hello->cipher_suites.size / S2N_SSLv2_CIPHER_SUITE_LEN));
} else {
POSIX_GUARD(s2n_set_cipher_as_tls_server(conn, client_hello->cipher_suites.data,
client_hello->cipher_suites.size / 2));
}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Would it make more sense for this branching to happen in s2n_set_cipher_as_tls_server?

Comment on lines +1249 to +1254
struct s2n_blob client_hello = {
.data = sslv2_client_hello,
.size = sizeof(sslv2_client_hello),
.allocated = 0,
.growable = 0
};
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We try to avoid directly instantiating blobs and stuffers. That bypasses any safety checks / additional initialization logic. I'm guessing you copied from the other test, but our best practices have gotten better ;)

Instead it should probably be:

Suggested change
struct s2n_blob client_hello = {
.data = sslv2_client_hello,
.size = sizeof(sslv2_client_hello),
.allocated = 0,
.growable = 0
};
struct s2n_blob client_hello = { 0 };
EXPECT_SUCCESS(s2n_blob_init(&client_hello, sslv2_client_hello), sizeof(sslv2_client_hello));

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants